home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0151.ZIP / INDEX80.C < prev    next >
Text File  |  1984-01-25  |  13KB  |  462 lines

  1. /********************************************************
  2. *                            *
  3. *            INDEX                *
  4. *           Text file index generator.        *
  5. *                            *
  6. *          T. Jennings 7/21/81            *
  7. *          235 Buchanan St             *
  8. *          San Francisco CA 94102        *
  9. *                             *
  10. *                            *
  11. *********************************************************
  12.  
  13.     INDEX Generates an ASCII WordStar (or equiv.) compatible
  14.     index from a text file. Words to be indexed are marked
  15.     with a control character. Entire phrases can be indexed
  16.     as well, by marking both ends with a different character.
  17.  
  18.     The index generated will be sorted alphabetically, with
  19.     the first character of all entries in caps. Each entry
  20.     will contain the page number as well.
  21.  
  22.     Two control characters, ^K and ^P are used. ^K marks
  23.     single words, and ^P marks phrases. Phrases too long
  24.     will be truncated to fit.
  25.  
  26. Examples: 
  27.     The sixth word in this ^Ksentence will be put in the index.
  28.  
  29.     ^PThis entire phrase^P will be indexed.
  30.  
  31.     The index for these two items, once printed, would look
  32.     like:
  33.  
  34.     Sentence .................................... 2
  35.     This entire phrase .......................... 3
  36.  
  37. See INDEX.DOC for details
  38. */
  39.  
  40. #include <bdscio.h>
  41. #define WORD_MARK 0x0b            /* The single word marker */
  42. #define    PHRASE_MARK 0x10        /* Phrase marker */
  43. #define CONTROLZ 0x1a
  44. #define CR 0x0d                /* useful ASCII characters */
  45. #define LF 0x0a
  46. #define WORD_LEN 39            /* maximum word or phrase size */
  47. #define LAST_COL 40            /* column to start page # */
  48. #define PAGE_LEN 66            /* default lines per page */
  49. #define DEF_LMARGIN 8            /* default left margin, */
  50. #define DEF_RMARGIN 72            /* ... and right margin */
  51.  
  52. char c;                    /* a useful variable for everyone */
  53. int char_count;                /* # characters looked at in file, */
  54. int word_count;                /* # words looked at */
  55. int line_count;                /* ditto lines */
  56. int this_line;                /* current line #/page */
  57. int entries;                /* # entries in index */
  58. int this_page;                /* current page */
  59. int page_size;                /* current max page length */
  60. int lmargin,rmargin;            /* current left and right margins */
  61. int found_index;            /* true if old index found */
  62.  
  63. char inbuf[BUFSIZ];            /* text input buffer */
  64. char outbuf[BUFSIZ];
  65. char inname[12];            /* where we save ASCII filenames */
  66. char outname[12];
  67. char tempname[12];
  68.  
  69. char pile[32768];    /* kludge */    /* Awaiting dynamic storage */
  70. char *i;                /* index pointer */
  71. char *pointers[1024];            /* pile pointers for sorting */
  72. change_page()                /* dummy function to start a new */
  73. {}                    /* page here. */
  74. /* System interface for INDEX. Make sure theres at least one argument (the
  75. filename). Open it for reading, (error check) make a temporary file for
  76. output (filename.$I$) (error check). Then...
  77.  
  78. 1/    Read the file sequentially, looking for marked words,     [ index()  ]
  79. 2/    Cleanup the pile of entries (remove leading blanks, convert each
  80.     1st character to uper case)                [ cleanup() ]
  81. 3/    Sort the pile alphabeticlly                [ sort()   ]
  82. 4/    Dump the pile to the disk, expanding each to correct width,
  83.     and removing duplicate entries                [ dump()  ]
  84. 5/    Return to CP/M
  85.  */
  86. main(argc,argv)
  87. int argc;
  88. char *argv[];
  89. {
  90.     printf ("\nINDEX-- Text file Index generator (c) T. Jennings 7/21/81");
  91.     page_size =PAGE_LEN;
  92.     lmargin =DEF_LMARGIN;
  93.     rmargin =DEF_RMARGIN;
  94.     found_index =FALSE;
  95.  
  96.     if (--argc >0)
  97.     {    strcpy (inname,argv[1]);    /* save the names, */
  98.         strcpy (outname,argv[1]);
  99.  
  100.         if (fopen(inname,inbuf) ==ERROR) /* try to open source file,*/
  101.         {    printf ("\nCan't open %s",inname);
  102.             exit();
  103.         }
  104.         add_ext (outname,"$I$");    /* make the output file, */
  105.         if (fcreat(outname,outbuf) ==ERROR) /* reuse and destroy name*/
  106.         {    printf ("\nCan't create temporary file %s",outname);
  107.             exit();
  108.         }
  109.     }
  110.     else
  111.     {    printf ("\nSpecify a file to make an index from");
  112.         exit();
  113.     }
  114.     printf ("\nAdding an index to %s (removing any old index first)",inname);
  115.     index();        /* scan the file, */
  116.     cleanup();        /* convert each 1st char to upper case */
  117.     printf ("\nSorting, ");
  118.     sort();            /* sort it, */
  119.     printf ("saving it, ");
  120.     dump();            /* write it to the disk, */
  121.     printf ("cleaning up, ");
  122.  
  123.     strcpy (tempname,inname);/* delete any .BAK */
  124.     add_ext (tempname,"BAK");
  125.     unlink (tempname);
  126.     rename (inname,tempname);/* rename original to .BAK, */
  127.     rename (outname,inname); /* rename new to original */
  128.  
  129.     printf ("done.\n");
  130.     exit();            /* exit. */
  131. }
  132. /* Read the input file, and make a list of words to index. Maintain
  133. the global variables indicating word count, etc. Leave a pile of
  134. strings, followed by the page #, terminated with a control-z. 
  135.  
  136. When done, PILE[] will have sequential null terminated strings, terminated
  137. by a single control-z. Each pointer in POINTERS[] will point to the start
  138. of each string, with the last pointing to the control-z.
  139.  
  140. KLUDGE: No limit check is done on the size of the pile, nor the size
  141. of POINTERS. (currently 1024 entries, 32 char. each) */
  142.  
  143. index()
  144. {
  145. int inword;            /* blank or character flag */
  146. int gotword;            /* true if saving this word */
  147. int gotphrase;            /* true if saving this phrase */
  148. int entry_len;            /* size of word or phrase */
  149. char linebuf[132];        /* character line buffer */
  150. int j;
  151. int last_char_blank;        /* suppress mult. spaces 'tween lines */
  152. int k;
  153.     inword =FALSE;        /* no word yet, */
  154.     gotword =FALSE;        /* no marked word found, */
  155.     gotphrase =FALSE;    /* no marked phrase found, */
  156.     last_char_blank =FALSE;    /* too early... */
  157.  
  158.     i =pile;         /* set the pointers, ... */
  159.     k=0;
  160.     char_count =0;
  161.     word_count =0;        /* and our booleans */
  162.     line_count =0;
  163.     entries =0;
  164.     this_page =1;
  165.     this_line =1;
  166.  
  167.     while (fill_line(linebuf) !=CONTROLZ)        /* while not EOF, */
  168.     {    if (scan_line(linebuf) ==TRUE)        /* look for dot cmds */
  169.             break;                /* get next line */
  170.         j=0;
  171.         ++line_count;                /* count total lines,*/
  172.         if (this_line++ >= page_size)        /* current line, */
  173.         {    this_line =1;
  174.             ++this_page;
  175.         }
  176.         while ((c =linebuf[j++]) !=0x00)    /* while not end/line*/
  177.         {    ++char_count;
  178.             if (c== ' ')
  179.             {    inword =FALSE;        /* end of a word */
  180.                 if (gotword)        /* if we were looking*/
  181.                 {    ++i;        /* leave null to mark*/
  182.                     sprintf(i,"%2d",this_page);
  183.                     while (*i++);    /* point to next */
  184.                      ++entries;    /* count another */
  185.                     gotword =FALSE;    /* done with word */
  186.                 }
  187.             }
  188.             else if (inword ==FALSE)    /* non-white char */
  189.             {    inword =TRUE;
  190.                 ++word_count;
  191.             }
  192.  
  193.             if (c==WORD_MARK)    /* new word to save */
  194.             {    gotword =TRUE;    /* start saving next char */
  195.                 entry_len =0;
  196.                 pointers[k++] =i;/* set the pointer */
  197.             }
  198.             else if (c== PHRASE_MARK)
  199.             {    if (gotphrase)    /* if we had one before, */
  200.                 {    ++i;    /* let the last null mark it */
  201.                     sprintf(i,"%2d",this_page);
  202.                     while (*i++);
  203.                     ++entries; /* counter another */
  204.                     gotphrase =FALSE;
  205.                 }
  206.                 else /* new phrase */
  207.                 {    gotphrase =TRUE; /* else start now. */
  208.                     entry_len =0;    /* just starting */
  209.                     pointers[k++] =i;/* point to it */
  210.                 }
  211.             }
  212.             /* see if we should store a character */
  213.             else if (  (gotphrase || gotword) &&
  214.                    (entry_len++ <WORD_LEN) &&
  215.                    (c >=' ') && (c !='.') &&
  216.                    !(last_char_blank && c==' ')  )
  217.             {    *i++ =c;    /* were saving now */
  218.                 *i =0x00;    /* null terminate it always, */
  219.                 last_char_blank= (c==' '? TRUE : FALSE);
  220.             }
  221.         }
  222.     }
  223.     *i =CONTROLZ;            /* mark the top of the pile, */
  224.     pointers[k++] =i;        /* set its pointer */
  225.     printf ("\n Put %d words in the index ",entries);
  226.     printf ("out of a total of %d words.",word_count);
  227.     return;
  228. }
  229. /* Sort routine. The array (pile) contains the index entries in no particular
  230. order. Array of pointers points to each entry. Put the entire pile in ascending
  231. alphabetic order. Very rude sort routine. (interchange) */
  232.  
  233. sort()
  234. {
  235. int first,last;
  236. char *temp;
  237. int changing;
  238.  
  239.     do
  240.     {
  241.         first =0;
  242.         last =1;
  243.         changing =FALSE;
  244.         while (*pointers[last] !=CONTROLZ)
  245.         {    if (comp (pointers[first],pointers[last]) >0)
  246.             {    temp =pointers[first];
  247.                 pointers[first] =pointers[last];
  248.                 pointers[last] =temp;
  249.                 changing =TRUE;
  250.             }
  251.             ++first; ++last;
  252.         }
  253.     }
  254.     while (changing);    /* until we make a do-nothing pass */
  255.     return;                        
  256. }
  257. /* Compare two strings. Return 0 if equal, >0 if first is greater than last,
  258. <0 if first less than last. Ignores case. */
  259.  
  260. int comp(first,last)
  261. char *first;
  262. char *last;
  263. {
  264. int i;
  265.     while (toupper(*first) ==toupper(*last) )
  266.     {    if (*first == 0x00)        /* stop at the null(if we got*/
  267.             return (0)        /* this far, it matched */
  268.         ;
  269.     ++first; ++last;
  270.     }
  271.     i =(toupper(*first) -toupper(*last));    /* mismatch */
  272.     return (i);
  273. }
  274. /* Compare two strings, of a given length. Check only for equality. Return
  275. 0 if equal, else 1. */
  276.  
  277. compl(length,first,last)
  278. int length;
  279. char *first,*last;
  280. {
  281.     for (; length >0; length--)
  282.     {    if (  (toupper(*first++)) != (toupper(*last++))  )
  283.             return (1)
  284.         ;
  285.     }
  286.     return (0);
  287. }
  288. /* Dump the pile to the disk. Convert each entry to a single line, making each
  289. an even number of columns wide. Put the page number at the end. Look for
  290. duplicate entries, and remove them. */
  291. dump()
  292. {
  293. int column;
  294. int i,x;
  295. char *current_entry;
  296. char *j;
  297. char c;
  298. int local_i;
  299.  
  300.     column =0;
  301.     i =0;
  302.     if (found_index ==FALSE)        /* dont duplicate this */
  303.     {    sendstr ("\015\012.pa");    /* if its already there */
  304.         sendstr ("\015\012..index\015\012");
  305.     }
  306.     while (*pointers[i] !=CONTROLZ)
  307.     {    j =pointers[i++];        /* send chars until null */
  308.         if (*j !=0xff)            /* if its a deleted dup copy, */
  309.         {                    /* skip this */
  310.             current_entry =j;        /* else save a copy, */
  311.             for (x =lmargin; x>0; x--)    /* tab to left margin */
  312.                 putc(' ',outbuf)
  313.             ;
  314.             while (c =*j++)
  315.             {    putc (c,outbuf);
  316.                 ++column;
  317.             }
  318.             while (column++ <LAST_COL)    /* make an entry */
  319.                 putc ('.',outbuf)    /* tab over, */
  320.             ;
  321.             putc (' ',outbuf);        /* type the page # */
  322.             while (c =*j++)
  323.                 putc (c,outbuf)
  324.             ;
  325. /* Look for duplicate entries; if we find one, remove it (mark 0xff) and 
  326. output it's page # on the current one. If more than 5, stop, and start the
  327. rest on the next line. */
  328.             local_i =0;
  329.             if (*pointers[i] !=CONTROLZ)
  330.             {    while ((comp(current_entry,pointers[i+local_i]) ==0) && (local_i <6) )
  331.                 {    j =pointers[i+local_i++];
  332.                     *j =0xff;    /* mark it removed */
  333.                     while (*j++)    /* skip the entry, */
  334.                     ;
  335.                     putc (',',outbuf);/* type a comma, */
  336.                     while (c =*j++)    /* send the page # */
  337.                         putc (c,outbuf)
  338.                     ;
  339.                 }
  340.             }
  341.             putc (CR,outbuf);        /* new line, */
  342.             putc (LF,outbuf);
  343.             column =0;            /* next line */
  344.         }
  345.     }
  346.     putc (CONTROLZ,outbuf);
  347.     fflush (outbuf);
  348.     fclose (outbuf);
  349.     return;
  350. }
  351. /* Fill a line buffer with characters. Convert all white_space characters
  352. to a single blank, put a null at the end. Copy each character to the output
  353. file. */
  354.  
  355. fill_line(buffer)
  356. char buffer[];
  357. {
  358. int i;
  359. char c;
  360. char d;
  361. int temp;
  362. int inblank;                /* true to suppress blanks */
  363.  
  364.     inblank =FALSE;
  365.     i=0;
  366.  
  367.     do
  368.     {    temp =getc(inbuf);
  369.         if (temp ==ERROR)
  370.             return (CONTROLZ)    /* check physical end */
  371.         ;
  372.         d =temp;            /* type conversion */
  373.         if (d ==CONTROLZ)        /* dont send the control-z */
  374.             return (d)
  375.         ;
  376.         putc (d,outbuf);
  377.         c =d&0x7f;
  378.         if (c== ' ' || c== ',' || c== '\t' || c==CR || c==LF
  379.            || c=='!' || c==';' || c==':' )
  380.             c=' '
  381.         ;
  382.         if ((c !=' ') || (inblank==FALSE))
  383.         {    buffer[i++] =c;
  384.             buffer[i] =0x00;
  385.         }
  386.         inblank =(c ==' ' ? TRUE : FALSE);
  387.         d &=0x7f;
  388.     }
  389.     while    ((d !=LF) && (d !=CONTROLZ) && (i <132))
  390.     ;
  391.     return(d);
  392. }
  393. /* Scan for dot commands. When and if we find a dot command, fool the 
  394. caller into thinking that the line we were passed is now empty. 
  395. If we find the index mark, "..index", set the flag so we dont duplicate
  396. it at dump time. */
  397.  
  398. scan_line(buffer)
  399. char *buffer;
  400. {
  401. int i;
  402.     while (*buffer ==' ')        /* skip leading blanks, */
  403.         ++buffer
  404.     ;
  405.     if (*buffer =='.')        /* as per WS specs, must be first atom */
  406.     {    if (compl (3,buffer,".pa") ==0)
  407.         {    ++this_page;
  408.             this_line =0;
  409.         }
  410.         else if (compl (7,buffer,"..index") ==0)
  411.         {    *buffer =0x00;
  412.             found_index =TRUE;
  413.             return (TRUE);
  414.         }
  415.     }
  416.     return (FALSE);
  417. }
  418. /* Clean up the pile by converting each first character to upper
  419. case. Deletes leading blanks by adjusting the pointer, but only if
  420. the string is more than 1 char long. */
  421.  
  422. cleanup()
  423. {
  424. int i;
  425. char c;
  426.     i =0;
  427.     while ((c= toupper(*pointers[i])) !=CONTROLZ)
  428.     {    if ((*pointers[i] ==' ') && (*pointers[i+1] !=0x00))
  429.         {    ++(pointers[i]);
  430.             c =toupper(*pointers[i]);
  431.         }
  432.         *pointers[i++] =c;
  433.     }
  434.     return;
  435. }
  436. /* Replace the extention on a filename, to the string we are passed. Note that
  437. only the first 3 chars are significant, and it is assumed the filename exists
  438. and is legal. */
  439. add_ext(filename,ext)
  440. char *filename;
  441. char *ext;
  442. {
  443. int i;
  444.     for (i=0; (i<9); i++)        /* look for the dot, or 8 chars, */
  445.     {    if ((*filename =='.') || (*filename ==0x00))
  446.             break
  447.         ;
  448.         filename++;
  449.     }
  450.     *filename++ ='.';        /* add a dot, */
  451.     while (*filename++ =*ext++)    /* the new extention */
  452.     ;
  453. }
  454. /* Send an ascii string to the output file */
  455. sendstr(string)
  456. char *string;
  457. {
  458.     while (*string)
  459.     {    putc (*string++,outbuf);
  460.     }
  461. }
  462.